#pragma once
#include "UltimatePhysX3Precompiled.h"
#include "UltimatePhysX3Subsystem.h"


//PxFilterFlags FilterShader (
//        PxFilterObjectAttributes attributes0, PxFilterData filterData0,
//        PxFilterObjectAttributes attributes1, PxFilterData filterData1,
//        PxPairFlags& pairFlags, const void* constantBlock, PxU32 constantBlockSize)
//{
//        // let triggers through
//        if(PxFilterObjectIsTrigger(attributes0) || PxFilterObjectIsTrigger(attributes1))
//        {
//                pairFlags = PxPairFlag::eTRIGGER_DEFAULT;
//                return PxFilterFlag::eDEFAULT;
//        }
//        // generate contacts for all that were not filtered above
//        pairFlags = PxPairFlag::eCONTACT_DEFAULT;
//
//        // trigger the contact callback for pairs (A,B) where
//        // the filtermask of A contains the ID of B and vice versa.
//        if((filterData0.word0 & filterData1.word1) && (filterData1.word0 & filterData0.word1))
//                pairFlags |= PxPairFlag::eNOTIFY_TOUCH_FOUND;
//
//        return PxFilterFlag::eDEFAULT;
//};


PxFilterFlags FilterShader (
	PxFilterObjectAttributes attributes0, PxFilterData filterData0,
	PxFilterObjectAttributes attributes1, PxFilterData filterData1,
	PxPairFlags& pairFlags, const void* constantBlock, PxU32 constantBlockSize)
{
	pairFlags = PxPairFlag::eCONTACT_DEFAULT;
	pairFlags |= PxPairFlag::eNOTIFY_TOUCH_FOUND;

	return PxFilterFlag::eDEFAULT;
};



UltimatePhysX3Subsystem::UltimatePhysX3Subsystem(void)
{
}


UltimatePhysX3Subsystem::~UltimatePhysX3Subsystem(void)
{
	mPhysics->release();
	mFoundation->release();
}

bool UltimatePhysX3Subsystem::initPhysics()
{

	mFoundation = PxCreateFoundation(PX_PHYSICS_VERSION, gDefaultAllocatorCallback, gDefaultErrorCallback);
	if(!mFoundation)
	{
		Ogre::LogManager::getSingletonPtr()->logMessage(Ogre::LML_CRITICAL,"PxCreateFoundation failed!");
	}

	bool recordMemoryAllocations = true;
	mPhysics = PxCreatePhysics(PX_PHYSICS_VERSION, *mFoundation,
		PxTolerancesScale(), recordMemoryAllocations, 0 );
	if(!mPhysics)
	{
		Ogre::LogManager::getSingletonPtr()->logMessage(Ogre::LML_CRITICAL,"PxCreatePhysics failed!");
	}

#ifdef WIN32
	// check if PvdConnection manager is available on this platform
	if(mPhysics->getPvdConnectionManager() == NULL)
		return false;

	// setup connection parameters
	const char*     pvd_host_ip = "127.0.0.1";  // IP of the PC which is running PVD
	int             port        = 5425;         // TCP port to connect to, where PVD is listening
	unsigned int    timeout     = 100;          // timeout in milliseconds to wait for PVD to respond,
	// consoles and remote PCs need a higher timeout.
	PxVisualDebuggerConnectionFlags connectionFlags = PxVisualDebuggerExt::getAllConnectionFlags();

	// and now try to connect
	debugger::comm::PvdConnection* theConnection = PxVisualDebuggerExt::createConnection(mPhysics->getPvdConnectionManager(),
		pvd_host_ip, port, timeout, connectionFlags);

	// remember to release the connection at shutdown
	if (theConnection)
		theConnection->release();
#endif

	return true;

}

UltimatePhysicsScene * UltimatePhysX3Subsystem::createPhysicsScene()
{

	PxSceneDesc sceneDesc(mPhysics->getTolerancesScale());
	//sceneDesc.gravity = PxVec3(0.0f, -9.81f, 0.0f);
	sceneDesc.gravity = PxVec3(0.0f, 0.0f, 0.0f);

	if(!sceneDesc.cpuDispatcher)
	{
		mCpuDispatcher = PxDefaultCpuDispatcherCreate(1);
		if(!mCpuDispatcher)
			Ogre::LogManager::getSingletonPtr()->logMessage(Ogre::LML_CRITICAL,"PxDefaultCpuDispatcherCreate failed!");
		sceneDesc.cpuDispatcher    = mCpuDispatcher;
	}
	if(!sceneDesc.filterShader)
		sceneDesc.filterShader    = FilterShader;


	mScene = mPhysics->createScene(sceneDesc);
	if (!mScene)
		Ogre::LogManager::getSingletonPtr()->logMessage(Ogre::LML_CRITICAL,"createScene failed!");

	mPhysX3Scene = new UltimatePhysX3Scene(mScene,mPhysics);
	mPhysX3Scene->initScene();

	return  mPhysX3Scene;
}

void  UltimatePhysX3Subsystem::destroyPhysicsScene()
{
	delete mPhysX3Scene;
}

